import java.util.HashSet;
import java.util.Random;
import java.util.Set;

/**
 * 加减法口算练习系统 V03
 * 功能：
 * 1. 生成50道不重复的加减法算式习题
 * 2. 每个算式显示答案
 * 3. 加法算式的和不超过100
 * 4. 减法算式的差不小于0
 * 5. 每行显示多个算式，整齐排列
 * 6. 确保加法和减法算式都有合理的出现比例
 */
public class CalculationSystemV03 {
    
    // 每行显示的算式数量
    private static final int EXERCISES_PER_ROW = 3;
    
    public static void main(String[] args) {
        System.out.println("加减法口算练习系统 V03");
        System.out.println("======================\n");
        
        // 生成50道不重复的习题
        generateUniqueExercises(50);
    }
    
    /**
     * 生成指定数量的不重复加减法习题
     * @param count 习题数量
     */
    public static void generateUniqueExercises(int count) {
        Random random = new Random();
        Set<String> generatedExercises = new HashSet<>(); // 用于存储已生成的算式字符串，确保不重复
        Exercise[] exercises = new Exercise[count];
        int index = 0;
        
        // 确保至少有25%的加法题和25%的减法题
        int minAdditions = Math.max(1, count / 4); // 至少1道加法题
        int minSubtractions = Math.max(1, count / 4); // 至少1道减法题
        int additionsCount = 0;
        int subtractionsCount = 0;
        
        // 先生成指定数量的加法题
        while (additionsCount < minAdditions && index < count) {
            Exercise exercise = generateExerciseWithAnswer(0, random); // 0表示加法
            String exerciseString = exercise.toStringWithoutAnswer();
            
            if (!generatedExercises.contains(exerciseString)) {
                generatedExercises.add(exerciseString);
                exercises[index++] = exercise;
                additionsCount++;
            }
        }
        
        // 先生成指定数量的减法题
        while (subtractionsCount < minSubtractions && index < count) {
            Exercise exercise = generateExerciseWithAnswer(1, random); // 1表示减法
            String exerciseString = exercise.toStringWithoutAnswer();
            
            if (!generatedExercises.contains(exerciseString)) {
                generatedExercises.add(exerciseString);
                exercises[index++] = exercise;
                subtractionsCount++;
            }
        }
        
        // 生成剩余的习题，随机选择加减法类型
        while (index < count) {
            // 随机选择运算类型，但如果某种类型还没达到最小数量要求，则强制选择该类型
            int operation;
            if (additionsCount < minAdditions) {
                operation = 0;
            } else if (subtractionsCount < minSubtractions) {
                operation = 1;
            } else {
                operation = random.nextInt(2);
            }
            
            Exercise exercise = generateExerciseWithAnswer(operation, random);
            String exerciseString = exercise.toStringWithoutAnswer();
            
            if (!generatedExercises.contains(exerciseString)) {
                generatedExercises.add(exerciseString);
                exercises[index++] = exercise;
                
                if (operation == 0) {
                    additionsCount++;
                } else {
                    subtractionsCount++;
                }
            }
        }
        
        // 输出所有生成的习题
        StringBuilder rowBuilder = new StringBuilder();
        for (int i = 0; i < exercises.length; i++) {
            // 格式化算式字符串，包括答案，总宽度约30个字符
            String formattedExercise = String.format("%2d. %-25s", (i + 1), exercises[i].toString());
            rowBuilder.append(formattedExercise);
            
            // 每行显示指定数量的算式
            if ((i + 1) % EXERCISES_PER_ROW == 0) {
                System.out.println(rowBuilder.toString());
                rowBuilder.setLength(0); // 清空StringBuilder
            } else if (i < exercises.length - 1) {
                rowBuilder.append("  "); // 算式之间的间隔
            }
        }
        
        // 如果最后一行不足指定数量的算式，也需要输出
        if (rowBuilder.length() > 0) {
            System.out.println(rowBuilder.toString());
        }
        
        // 输出统计信息
        System.out.println("\n统计信息：");
        System.out.println("总题数：" + count);
        System.out.println("加法题：" + additionsCount + " 题 (" + (additionsCount * 100 / count) + "%)");
        System.out.println("减法题：" + subtractionsCount + " 题 (" + (subtractionsCount * 100 / count) + "%)");
    }
    
    /**
     * 根据运算类型生成一道习题及答案
     * @param operation 运算类型 (0: 加法, 1: 减法)
     * @param random 随机数生成器
     * @return 生成的习题对象，包含算式和答案
     */
    public static Exercise generateExerciseWithAnswer(int operation, Random random) {
        int num1, num2, answer;
        String operator;
        
        if (operation == 0) { // 加法
            operator = "+";
            // 为保证结果在100以内，两个数之和不超过100
            num1 = random.nextInt(100); // 0-99
            num2 = random.nextInt(101 - num1); // 保证num1 + num2 <= 100
            answer = num1 + num2;
        } else { // 减法
            operator = "-";
            // 为保证结果为非负数，被减数大于等于减数
            num1 = random.nextInt(100) + 1; // 1-100
            num2 = random.nextInt(num1 + 1); // 0-num1
            answer = num1 - num2;
        }
        
        return new Exercise(num1, num2, operator, answer);
    }
    
    /**
     * 习题类，用于存储算式的各个部分和答案
     */
    static class Exercise {
        private int num1;
        private int num2;
        private String operator;
        private int answer;
        
        public Exercise(int num1, int num2, String operator, int answer) {
            this.num1 = num1;
            this.num2 = num2;
            this.operator = operator;
            this.answer = answer;
        }
        
        /**
         * 返回包含答案的算式字符串
         */
        @Override
        public String toString() {
            // 格式：数字1 运算符 数字2 = 答案
            return num1 + " " + operator + " " + num2 + " = " + answer;
        }
        
        /**
         * 返回不包含答案的算式字符串，用于判断重复
         */
        public String toStringWithoutAnswer() {
            // 格式：数字1 运算符 数字2
            return num1 + " " + operator + " " + num2;
        }
    }
}